home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / app.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-30  |  33.1 KB  |  1,198 lines

  1. unit App;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, Windows, Messages, Classes, Graphics, Controls,
  7.   Forms, Dialogs, ToolIntf, StdCtrls, Buttons, ExtCtrls, ComCtrls;
  8.  
  9. type
  10.   TMoveDirection = (mdPrevious, mdNext, mdNoMove);
  11.  
  12.   TAppExpert = class(TForm)
  13.     Sample: TPaintBox;
  14.     CancelBtn: TButton;
  15.     PrevButton: TButton;
  16.     NextButton: TButton;
  17.     PageControl: TPageControl;
  18.     Menus: TTabSheet;
  19.     Label1: TLabel;
  20.     Label2: TLabel;
  21.     Label3: TLabel;
  22.     Label4: TLabel;
  23.     Label5: TLabel;
  24.     cbFileMenu: TCheckBox;
  25.     cbEditMenu: TCheckBox;
  26.     cbWindowMenu: TCheckBox;
  27.     cbHelpMenu: TCheckBox;
  28.     Extensions: TTabSheet;
  29.     Label6: TLabel;
  30.     Panel1: TPanel;
  31.     ExtHeader: THeader;
  32.     ExtListBox: TListBox;
  33.     AddButton: TButton;
  34.     EditButton: TButton;
  35.     DeleteButton: TButton;
  36.     UpButton: TButton;
  37.     DownButton: TButton;
  38.     Speedbtns: TTabSheet;
  39.     Label7: TLabel;
  40.     Speedbar: TPaintBox;
  41.     Label8: TLabel;
  42.     Label9: TLabel;
  43.     MenuList: TListBox;
  44.     MenuItemList: TListBox;
  45.     Button1: TButton;
  46.     Button2: TButton;
  47.     Button3: TButton;
  48.     AppInfo: TTabSheet;
  49.     Label13: TLabel;
  50.     Label10: TLabel;
  51.     Label15: TLabel;
  52.     GroupBox1: TGroupBox;
  53.     cbMDIApp: TCheckBox;
  54.     cbStatusLine: TCheckBox;
  55.     cbHints: TCheckBox;
  56.     AppPath: TEdit;
  57.     PathBrowse: TButton;
  58.     AppName: TEdit;
  59.     procedure FormCreate(Sender: TObject);
  60.     procedure NextPrevClick(Sender: TObject);
  61.     procedure DrawExtension(Control: TWinControl; Index: Integer;
  62.       Rect: TRect; State: TOwnerDrawState);
  63.     procedure AddClick(Sender: TObject);
  64.     procedure HeaderSized(Sender: TObject; ASection, AWidth: Integer);
  65.     procedure EditClick(Sender: TObject);
  66.     procedure DeleteClick(Sender: TObject);
  67.     procedure MoveClick(Sender: TObject);
  68.     procedure SpeedbarPaint(Sender: TObject);
  69.     procedure FormDestroy(Sender: TObject);
  70.     procedure MenuListClick(Sender: TObject);
  71.     procedure DrawMenuItem(Control: TWinControl; Index: Integer;
  72.       Rect: TRect; State: TOwnerDrawState);
  73.     procedure InsertClick(Sender: TObject);
  74.     procedure SpaceClick(Sender: TObject);
  75.     procedure SpeedMouseDown(Sender: TObject; Button: TMouseButton;
  76.       Shift: TShiftState; X, Y: Integer);
  77.     procedure RemoveClick(Sender: TObject);
  78.     procedure BrowseClick(Sender: TObject);
  79.     procedure SamplePaint(Sender: TObject);
  80.     procedure MenuClicked(Sender: TObject);
  81.   private
  82.     { Private declarations }
  83.     SpeedList: TList;
  84.     ButtonList: TList;
  85.     FSpeedIndex: Integer;
  86.     SpeedPointer: TBitmap;
  87.     Offscreen: TBitmap;
  88.     SampleBmp: TBitmap;
  89.     procedure RefreshButtons;
  90.     function NextPage(Direction: TMoveDirection): Integer;
  91.     function SpeedButtonRect(Index: Integer): TRect;
  92.     function SpeedButtonAtPos(Pos: TPoint): Integer;
  93.     function GetSpeedButtonCount: Integer;
  94.     function GetSpeedButtonID(Value: Integer): Integer;
  95.     function ValidateInfo: Boolean;
  96.   public
  97.     { Public declarations }
  98.     function HasMenus: Boolean;
  99.     property SpeedButtonCount: Integer read GetSpeedButtonCount;
  100.     property SpeedButtonID[Value: Integer]: Integer read GetSpeedButtonID;
  101.   end;
  102. var
  103.   AppExpert: TAppExpert;
  104.  
  105. procedure ApplicationExpert(ToolServices: TIToolServices);
  106.  
  107. implementation
  108.  
  109. uses ExConst, Filters, FileCtrl;
  110.  
  111. {$R *.DFM}
  112.  
  113. const
  114.   { page numbers }
  115.   pgMenus   = 0;
  116.   pgExtensions = 1;
  117.   pgSpeedbar = 2;
  118.   pgAppInfo = 3;
  119.  
  120.   FirstPage = pgMenus;
  121.   LastPage = pgAppInfo;
  122.  
  123.   DefaultButtonSize: TPoint = (X: 24; Y: 24);
  124.   DefaultButtonSpace: Integer = 6;
  125.  
  126.   MenuItemCount = 18;
  127.  
  128. type
  129.   TMainItems = (mmFile, mmEdit, mmWindow, mmHelp);
  130.  
  131. const
  132.   MenuItemCounts: array[TMainItems] of Integer = (7, 4, 3, 4);
  133.   MenuItemOffsets: array[TMainItems] of Integer = (0, 7, 11, 14);
  134.   SampleBitmaps: array[FirstPage..LastPage] of PChar = (
  135.     'MENUDSGN', 'EXTDSGN', 'SPEEDDSGN', 'INFODSGN');
  136.  
  137. { TButtonImage - draws the image of a TSpeedButton }
  138. type
  139.   TButtonImage = class(TObject)
  140.   private
  141.     FBitmapID: Word;
  142.     FBitmap: TBitmap;
  143.     FNumGlyphs: Integer;
  144.     procedure SetBitmapID(Value: Word);
  145.   public
  146.     constructor Create;
  147.     destructor Destroy; override;
  148.     procedure Draw(Canvas: TCanvas; X, Y: Integer);
  149.     property BitmapID: Word read FBitmapID write SetBitmapID;
  150.     property NumGlyphs: Integer read FNumGlyphs write FNumGlyphs;
  151.   end;
  152.  
  153. { Code generation support }
  154. type
  155.   TCodeSnipet = (csProgram, csMainIntf, csMainImpl, csFormCreateProc,
  156.     csShowHelpProc, csFileNewProc, csFileOpenProc, csFileSaveProc,
  157.     csFileSaveAsProc, csFilePrintProc, csFilePrintSetupProc, csFileExitProc,
  158.     csEditUndoProc, csEditCutProc, csEditCopyProc, csEditPasteProc,
  159.     csWindowTileProc, csWindowCascadeProc, csWindowArrangeProc,
  160.     csHelpContentsProc, csHelpSearchProc, csHelpHowToUseProc,
  161.     csHelpAboutProc, csForm, csFormMenu, csCreateMethod, csFormMDI, csHints,
  162.     csMenuObject, csFileMenuObject, csEditMenuObject, csWindowMenuObject,
  163.     csHelpMenuObject, csOpenDialogObject, csSaveDialogObject,
  164.     csPrintDialogObject, csPrintSetupDialogObject, csStatusLineObject,
  165.     csSpeedbarObject, csSpeedButtonObject);
  166.  
  167. const
  168.   SourceBufferSize = 1024;
  169.  
  170. var
  171.   CodeSnipets: array[TCodeSnipet] of PChar;
  172.   CodeResource: THandle;
  173.   SourceBuffer: PChar;
  174.   ResourceBuffer: PChar;
  175.  
  176. procedure InitCodeGeneration;
  177. var
  178.   ResourceSize: Integer;
  179.   ResourcePtr, Text: PChar;
  180.   SnipetIndex: TCodeSnipet;
  181. begin
  182.   SourceBuffer := StrAlloc(SourceBufferSize);
  183.  
  184.   ResourceSize := SizeofResource(HInstance,
  185.     FindResource(HInstance, 'SNIPETS', RT_RCDATA));
  186.   CodeResource := LoadResource(HInstance,
  187.     FindResource(HInstance, 'SNIPETS', RT_RCDATA));
  188.   ResourcePtr := LockResource(CodeResource);
  189.   ResourceBuffer := StrAlloc(ResourceSize);
  190.   Move(ResourcePtr^, ResourceBuffer^, ResourceSize);
  191.   Text := ResourceBuffer;
  192.   for SnipetIndex := Low(TCodeSnipet) to High(TCodeSnipet) do
  193.   begin
  194.     CodeSnipets[SnipetIndex] := Text;
  195.     while Text^ <> '|' do 
  196.       if Text^ in LeadBytes then Inc(Text, 2) else Inc(Text);
  197.     Text^ := #0;
  198.     Inc(Text);
  199.   end;
  200. end;
  201.  
  202. procedure DoneCodeGeneration;
  203. begin
  204.   StrDispose(SourceBuffer);
  205.   UnlockResource(CodeResource);
  206.   FreeResource(CodeResource);
  207.   StrDispose(ResourceBuffer);
  208. end;
  209.  
  210. procedure BinToHex(Binary, Text: PChar; Count: Integer);
  211. const
  212.   HexChars: array[0..15] of Char = '0123456789ABCDEF';
  213. var
  214.   I: Integer;
  215. begin
  216.   for I := 0 to Count - 1 do
  217.   begin
  218.     Text^ := HexChars[(Byte(Binary[I]) and $F0) SHR 4];
  219.     Inc(Text);
  220.     Text^ := HexChars[(Byte(Binary[I]) and $0F)];
  221.     Inc(Text);
  222.   end;
  223. end;
  224.  
  225. procedure WriteBinaryAsText(Input: TStream; Output: TStream);
  226. const
  227.   BytesPerLine = 32;
  228.   NewLine: PChar = #13#10;
  229. var
  230.   MultiLine: Boolean;
  231.   I: Integer;
  232.   Count: Longint;
  233.   Buffer: array[0..BytesPerLine - 1] of Char;
  234.   Text: array[0..BytesPerLine * 2 - 1] of Char;
  235. begin
  236.   Count := Input.Size;
  237.   MultiLine := Count > BytesPerLine;
  238.   BinToHex(@Count, Text, 4);
  239.   Output.Write(Text, 4 * 2);
  240.  
  241.   while Count > 0 do
  242.   begin
  243.     if MultiLine then Output.Write(NewLine[0], 2);
  244.     if Count >= BytesPerLine then I := BytesPerLine else I := Count;
  245.     Input.Read(Buffer, I);
  246.     BinToHex(Buffer, Text, I);
  247.     Output.Write(Text, I * 2);
  248.     Dec(Count, I);
  249.   end;
  250. end;
  251.  
  252. procedure FmtWrite(Stream: TStream; Fmt: PChar; const Args: array of const);
  253. begin
  254.   StrLFmt(SourceBuffer, SourceBufferSize, Fmt, Args);
  255.   Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
  256. end;
  257.  
  258. procedure WriteSnipet(Stream: TStream; Snipet: TCodeSnipet);
  259. begin
  260.   Stream.Write(CodeSnipets[Snipet][0], StrLen(CodeSnipets[Snipet]));
  261. end;
  262.  
  263. procedure WriteIdent(Stream: TStream; ResID: Word; const VarType: string);
  264. begin
  265.   StrPCopy(SourceBuffer, Format('    %s: %s;'#13#10, [LoadStr(ResID), VarType]));
  266.   Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
  267. end;
  268.  
  269. procedure WriteMenuItems(Stream: TStream; MenuIndex: TMainItems);
  270. var
  271.   I: Integer;
  272. begin
  273.   for I := 0 to MenuItemCounts[MenuIndex] - 1 do
  274.     WriteIdent(Stream, sMenuItemNameBase + MenuItemOffsets[MenuIndex] + I,
  275.       'TMenuItem');
  276. end;
  277.  
  278. procedure WriteMethodDecl(Stream: TStream; ResID: Word);
  279. begin
  280.   StrPCopy(SourceBuffer, Format('    procedure %s(Sender: TObject);'#13#10,
  281.     [LoadStr(ResID)]));
  282.   Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
  283. end;
  284.  
  285. procedure WriteMethodHeader(Stream: TStream; ResID: Word);
  286. begin
  287.   StrPCopy(SourceBuffer, Format('procedure T%s.%s(Sender: TObject);'#13#10,
  288.     [LoadStr(sMainForm), LoadStr(ResID)]));
  289.   Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
  290. end;
  291.  
  292. procedure WriteMenuMethodDecls(Stream: TStream; MenuIndex: TMainItems);
  293. var
  294.   I: Integer;
  295. begin
  296.   for I := 0 to MenuItemCounts[MenuIndex] - 1 do
  297.     WriteMethodDecl(Stream, sMenuProcNames + MenuItemOffsets[MenuIndex] + I);
  298. end;
  299.  
  300. procedure WriteMenuMethods(Stream: TStream; MenuIndex: TMainItems;
  301.   BaseSnipet: TCodeSnipet);
  302. var
  303.   ID, I: Integer;
  304.   Snipet: TCodeSnipet;
  305. begin
  306.   ID := sMenuProcNames + MenuItemOffsets[MenuIndex];
  307.   for I := 0 to MenuItemCounts[MenuIndex] - 1 do
  308.   begin
  309.     WriteMethodHeader(Stream, ID + I);
  310.     Snipet := TCodeSnipet( I + Ord(BaseSnipet) );
  311.     WriteSnipet(Stream, Snipet);
  312.   end;
  313. end;
  314.  
  315. procedure WriteGlyphData(Stream: TStream; BitmapID: Word);
  316. var
  317.   Bitmap: TBitmap;
  318.   Memory: TMemoryStream;
  319. begin
  320.   Bitmap := TBitmap.Create;
  321.   try
  322.     Bitmap.Handle := LoadBitmap(HInstance, PChar(BitmapID));
  323.  
  324.     { stream the bitmap to a memory stream, and the write that stream as text }
  325.     Memory := TMemoryStream.Create;
  326.     try
  327.       Bitmap.SaveToStream(Memory);
  328.       Memory.Position := 0;
  329.       WriteBinaryAsText(Memory, Stream);
  330.     finally
  331.       Memory.Free;
  332.     end;
  333.  
  334.   finally
  335.     Bitmap.Free;
  336.   end;
  337.   FmtWrite(Stream, '}'#13#10'end'#13#10, [nil]);
  338. end;
  339.  
  340. function GenerateProjectSource(AppExpert: TAppExpert): TFileName;
  341. var
  342.   ProjectFile: TFileStream;
  343. begin
  344.   Result := AppExpert.AppPath.Text;
  345.   if (Result > '') and not (AnsiLastChar(Result)^ in [':', '\']) then
  346.     Result := Result + '\';
  347.   Result := Result + AppExpert.AppName.Text + '.DPR';
  348.  
  349.   ProjectFile := TFileStream.Create(Result, fmCreate);
  350.   try
  351.     StrFmt(SourceBuffer, CodeSnipets[csProgram], [AppExpert.AppName.Text]);
  352.     ProjectFile.Write(SourceBuffer[0], StrLen(SourceBuffer));
  353.   finally
  354.     ProjectFile.Free;
  355.   end;
  356. end;
  357.  
  358. procedure GenerateMainSourceFile(AppExpert: TAppExpert);
  359. var
  360.   Stream: TFileStream;
  361.   FileName: TFileName;
  362.   ButtonName: string[80];
  363.   ButtonText: string[30];
  364.   ButtonID: Integer;
  365.   I: Integer;
  366. begin
  367.   FileName := AppExpert.AppPath.Text;
  368.   if (FileName > '') and not (AnsiLastChar(FileName)^ in [':', '\']) then
  369.     FileName := FileName + '\';
  370.   FileName := FileName + LoadStr(sMainSourceFile);
  371.  
  372.   Stream := TFileStream.Create(FileName, fmCreate);
  373.   try
  374.     WriteSnipet(Stream, csMainIntf);
  375.  
  376.     SourceBuffer[0] := #0;
  377.  
  378.     { create the menu declarations }
  379.     if AppExpert.HasMenus then
  380.     begin
  381.       WriteIdent(Stream, sMainMenu, 'TMainMenu');
  382.       if AppExpert.cbFileMenu.Checked then WriteMenuItems(Stream, mmFile);
  383.       if AppExpert.cbEditMenu.Checked then WriteMenuItems(Stream, mmEdit);
  384.       if AppExpert.cbWindowMenu.Checked then WriteMenuItems(Stream, mmWindow);
  385.       if AppExpert.cbHelpMenu.Checked then WriteMenuItems(Stream, mmHelp);
  386.      end;
  387.  
  388.     { create any variable declarations }
  389.     if AppExpert.cbStatusLine.Checked then
  390.       WriteIdent(Stream, sStatusLine, 'TStatusBar');
  391.  
  392.     if AppExpert.cbFileMenu.Checked then
  393.     begin
  394.       WriteIdent(Stream, sOpenDialog, 'TOpenDialog');
  395.       WriteIdent(Stream, sSaveDialog, 'TSaveDialog');
  396.       WriteIdent(Stream, sPrintDialog, 'TPrintDialog');
  397.       WriteIdent(Stream, sPrintSetupDialog, 'TPrinterSetupDialog');
  398.     end;
  399.  
  400.     { create speedbuttons }
  401.     if AppExpert.SpeedButtonCount > 0 then
  402.     begin
  403.       WriteIdent(Stream, sSpeedBar, 'TPanel');
  404.  
  405.       ButtonName := '    ' + LoadStr(sSpeedButton) +
  406.         ': TSpeedButton;  { %s }'#13#10;
  407.  
  408.       ButtonID := 1;
  409.       for I := 0 to AppExpert.SpeedButtonCount - 1 do
  410.       begin
  411.         if AppExpert.SpeedButtonID[I] > -1 then
  412.         begin
  413.           ButtonText := LoadStr(AppExpert.SpeedButtonID[I]);
  414.           StrPCopy(SourceBuffer, Format(ButtonName, [ButtonID, ButtonText]));
  415.           Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
  416.           Inc(ButtonID);
  417.         end;
  418.       end;
  419.     end;
  420.  
  421.     { generate method declarations }
  422.     if AppExpert.cbStatusLine.Checked and AppExpert.cbHints.Checked then
  423.     begin
  424.       WriteMethodDecl(Stream, sFormCreateProc);
  425.       WriteMethodDecl(Stream, sShowHelpProc);
  426.     end;
  427.  
  428.     if AppExpert.cbFileMenu.Checked then WriteMenuMethodDecls(Stream, mmFile);
  429.     if AppExpert.cbEditMenu.Checked then WriteMenuMethodDecls(Stream, mmEdit);
  430.     if AppExpert.cbWindowMenu.Checked then WriteMenuMethodDecls(Stream, mmWindow);
  431.     if AppExpert.cbHelpMenu.Checked then WriteMenuMethodDecls(Stream, mmHelp);
  432.  
  433.     WriteSnipet(Stream, csMainImpl);
  434.  
  435.     { write code implementations }
  436.     if AppExpert.cbStatusLine.Checked and AppExpert.cbHints.Checked then
  437.     begin
  438.       WriteMethodHeader(Stream, sFormCreateProc);
  439.       WriteSnipet(Stream, csFormCreateProc);
  440.       WriteMethodHeader(Stream, sShowHelpProc);
  441.       WriteSnipet(Stream, csShowHelpProc);
  442.     end;
  443.  
  444.     if AppExpert.cbFileMenu.Checked then
  445.       WriteMenuMethods(Stream, mmFile, csFileNewProc);
  446.  
  447.     if AppExpert.cbEditMenu.Checked then
  448.       WriteMenuMethods(Stream, mmEdit, csEditUndoProc);
  449.  
  450.     if AppExpert.cbWindowMenu.Checked then
  451.       WriteMenuMethods(Stream, mmWindow, csWindowTileProc);
  452.  
  453.     if AppExpert.cbHelpMenu.Checked then
  454.       WriteMenuMethods(Stream, mmHelp, csHelpContentsProc);
  455.  
  456.     FmtWrite(Stream, 'end.'#13#10, [nil]);
  457.  
  458.   finally
  459.     Stream.Free;
  460.   end;
  461. end;
  462.  
  463. procedure GenerateMainFormFile(AppExpert: TAppExpert);
  464. const
  465.   ButtonWidth = 25;
  466.   SpaceWidth = 4;
  467. var
  468.   TextStream: TFileStream;
  469.   FormStream: TFileStream;
  470.   TextName: TFileName;
  471.   FormName: TFileName;
  472.   Filter: string;
  473.   ButtonNumber: Integer;
  474.   ButtonID: Integer;
  475.   ButtonMethod: string;
  476.   ButtonHint: string;
  477.   ButtonX: Integer;
  478.   I: Integer;
  479. begin
  480.   TextName := AppExpert.AppPath.Text;
  481.   if (TextName > '') and not (AnsiLastChar(TextName)^ in [':', '\']) then
  482.     TextName := TextName + '\';
  483.   FormName := TextName + LoadStr(sMainFormFile);
  484.   TextName := TextName + LoadStr(sMainFormText);
  485.  
  486.   TextStream := TFileStream.Create(TextName, fmCreate);
  487.   try
  488.     WriteSnipet(TextStream, csForm);
  489.     if AppExpert.cbMDIApp.Checked then WriteSnipet(TextStream, csFormMDI);
  490.     if AppExpert.HasMenus then WriteSnipet(TextStream, csFormMenu);
  491.     if AppExpert.cbHints.Checked then
  492.     begin
  493.       WriteSnipet(TextStream, csHints);
  494.       if AppExpert.cbStatusLine.Checked then
  495.         WriteSnipet(TextStream, csCreateMethod);
  496.     end;
  497.  
  498.     { write menus }
  499.     if AppExpert.HasMenus then
  500.     begin
  501.       WriteSnipet(TextStream, csMenuObject);
  502.  
  503.       if AppExpert.cbFileMenu.Checked then
  504.         WriteSnipet(TextStream, csFileMenuObject);
  505.       if AppExpert.cbEditMenu.Checked then
  506.         WriteSnipet(TextStream, csEditMenuObject);
  507.       if AppExpert.cbWindowMenu.Checked then
  508.         WriteSnipet(TextStream, csWindowMenuObject);
  509.       if AppExpert.cbHelpMenu.Checked then
  510.         WriteSnipet(TextStream, csHelpMenuObject);
  511.  
  512.       FmtWrite(TextStream, '  end'#13#10, [nil]);
  513.  
  514.       if AppExpert.cbFileMenu.Checked then
  515.       begin
  516.         { create the dialog objects }
  517.         Filter := '';
  518.         for I := 0 to AppExpert.ExtListBox.Items.Count - 1 do
  519.           Filter := Filter + AppExpert.ExtListBox.Items[I] + '|';
  520.         if AnsiLastChar(Filter) = '|' then
  521.           Delete(Filter, Length(Filter), 1);
  522.  
  523.         FmtWrite(TextStream, CodeSnipets[csOpenDialogObject], [Filter]);
  524.         FmtWrite(TextStream, CodeSnipets[csSaveDialogObject], [Filter]);
  525.         WriteSnipet(TextStream, csPrintDialogObject);
  526.         WriteSnipet(TextStream, csPrintSetupDialogObject);
  527.       end;
  528.  
  529.     end;
  530.  
  531.     if AppExpert.cbStatusLine.Checked then
  532.       WriteSnipet(TextStream, csStatusLineObject);
  533.  
  534.     { create speedbuttons }
  535.     if AppExpert.SpeedButtonCount > 0 then
  536.     begin
  537.       WriteSnipet(TextStream, csSpeedbarObject);
  538.  
  539.       ButtonNumber := 0;
  540.       ButtonX := 8;
  541.  
  542.       for I := 0 to AppExpert.SpeedButtonCount - 1 do
  543.       begin
  544.         if AppExpert.SpeedButtonID[I] > -1 then
  545.         begin
  546.           Inc(ButtonNumber);
  547.           ButtonID := AppExpert.SpeedButtonID[I] - sMenuItemTextBase;
  548.           ButtonMethod := LoadStr(ButtonID + sMenuProcNames);
  549.           ButtonHint := LoadStr(ButtonID + sHintBase);
  550.           FmtWrite(TextStream, CodeSnipets[csSpeedButtonObject],
  551.             [ButtonNumber, ButtonX, ButtonMethod, ButtonHint]);
  552.           WriteGlyphData(TextStream, ButtonID + 11100);
  553.           Inc(ButtonX, ButtonWidth - 1);
  554.         end
  555.         else Inc(ButtonX, SpaceWidth);
  556.       end;
  557.  
  558.       FmtWrite(TextStream, '  end'#13#10, [nil]);
  559.     end;
  560.  
  561.     FmtWrite(TextStream, 'end'#13#10, [nil]);
  562.  
  563.     { reset the text stream for conversion }
  564.     TextStream.Position := 0;
  565.  
  566.     FormStream := TFileStream.Create(FormName, fmCreate);
  567.     try
  568.       ObjectTextToResource(TextStream, FormStream);
  569.     finally
  570.       FormStream.Free;
  571.     end;
  572.  
  573.   finally
  574.     TextStream.Free;
  575.   end;
  576. end;
  577.  
  578. { interface procedure }
  579. procedure ApplicationExpert(ToolServices: TIToolServices);
  580. var
  581.   D: TAppExpert;
  582.   ProjectName: TFileName;
  583. begin
  584.   D := TAppExpert.Create(Application);
  585.   try
  586.     if D.ShowModal = mrOK then
  587.     begin
  588.  
  589.       InitCodeGeneration;
  590.       try
  591.         ProjectName := ExpandFileName(GenerateProjectSource(D));
  592.         GenerateMainSourceFile(D);
  593.         GenerateMainFormFile(D);
  594.       finally
  595.         DoneCodeGeneration;
  596.       end;
  597.  
  598.       { open the new project }
  599.       if (ToolServices <> nil) and ToolServices.CloseProject then
  600.         ToolServices.OpenProject(ProjectName);
  601.     end;
  602.   finally
  603.     D.Free;
  604.   end;
  605. end;
  606.  
  607. function EditFilterInfo(var Filter: string): Boolean;
  608. var
  609.   D: TFilterDlg;
  610. begin
  611.   D := TFilterDlg.Create(Application);
  612.   try
  613.     D.Filter := Filter;
  614.     Result := D.ShowModal = mrOK;
  615.     if Result then Filter := D.Filter;
  616.   finally
  617.     D.Free;
  618.   end;
  619. end;
  620.  
  621. procedure ClearButtonImages(List: TList);
  622. var
  623.   I: Integer;
  624. begin
  625.   for I := 0 to List.Count - 1 do
  626.     TButtonImage(List[I]).Free;
  627.   List.Clear;
  628. end;
  629.  
  630. { TButtonImage }
  631. constructor TButtonImage.Create;
  632. begin
  633.   FBitmap := TBitmap.Create;
  634.   FNumGlyphs := 1;
  635. end;
  636.  
  637. destructor TButtonImage.Destroy;
  638. begin
  639.   FBitmap.Free;
  640.   inherited Destroy;
  641. end;
  642.  
  643. procedure TButtonImage.SetBitmapID(Value: Word);
  644. begin
  645.   if FBitmapID <> Value then
  646.   begin
  647.     FBitmapID := Value;
  648.     FBitmap.Handle := LoadBitmap(HInstance, PChar(FBitmapID));
  649.   end;
  650. end;
  651.  
  652. procedure TButtonImage.Draw(Canvas: TCanvas; X, Y: Integer);
  653. var
  654.   BX: Integer;
  655.   Target: TRect;
  656.   Source: TRect;
  657.   SavePen, SaveBrush: TColor;
  658. begin
  659.   with Canvas do
  660.   begin
  661.     SavePen := Canvas.Pen.Color;
  662.     SaveBrush := Canvas.Brush.Color;
  663.  
  664.     Target := DrawButtonFace(Canvas, Bounds(X, Y, DefaultButtonSize.X,
  665.       DefaultButtonSize.Y), 1, bsWin31, False, False, False);
  666.  
  667.     { draw bitmap }
  668.     BX := FBitmap.Width div FNumGlyphs;
  669.     if BX > 0 then
  670.     begin
  671.       Target := Bounds(X, Y, BX, FBitmap.Height);
  672.       OffsetRect(Target, (DefaultButtonSize.X div 2) - (BX div 2),
  673.         (DefaultButtonSize.Y div 2) - (FBitmap.Height div 2));
  674.       Source := Bounds(0, 0, BX, FBitmap.Height);
  675.       BrushCopy(Target, FBitmap, Source,
  676.         FBitmap.Canvas.Pixels[0, FBitmap.Height - 1]);
  677.     end;
  678.  
  679.     Canvas.Pen.Color := SavePen;
  680.     Canvas.Brush.Color := SaveBrush;
  681.   end;
  682. end;
  683.  
  684.  
  685. { TAppExpert }
  686. procedure TAppExpert.FormCreate(Sender: TObject);
  687. var
  688.   ID: Word;
  689.   ButtonImage: TButtonImage;
  690. begin
  691.   SpeedList := TList.Create;
  692.   ButtonList := TList.Create;
  693.   SpeedPointer := TBitmap.Create;
  694.   SpeedPointer.Handle := LoadBitmap(HInstance, 'SPEEDPOINTER');
  695.   Offscreen := TBitmap.Create;
  696.   Offscreen.Width := SpeedBar.Width;
  697.   Offscreen.Height := SpeedBar.Height;
  698.  
  699.   SampleBmp := TBitmap.Create;
  700.  
  701.   { fill the MenuItemList with the speedbuttons }
  702.   for ID := sMenuItemTextBase to sMenuItemTextBase + MenuItemCount - 1 do
  703.   begin
  704.     ButtonImage := TButtonImage.Create;
  705.     ButtonImage.NumGlyphs := 2;
  706.     ButtonImage.BitmapID := ID;
  707.     ButtonList.Add(ButtonImage);
  708.   end;
  709.  
  710.   { This is required to prevent the speedbar from erasing its background
  711.     each time it paints.  This dramatically reduces (eliminates) any
  712.     flicker when painting. (Try commenting out this line to see the
  713.     difference) }
  714.   SpeedBar.ControlStyle := [csOpaque];
  715.  
  716.   PageControl.ActivePage := PageControl.Pages[FirstPage];
  717.   SampleBmp.Handle := LoadBitmap(HInstance, SampleBitmaps[FirstPage]);
  718.  
  719.   RefreshButtons;
  720. end;
  721.  
  722. procedure TAppExpert.FormDestroy(Sender: TObject);
  723. begin
  724.   ClearButtonImages(ButtonList);
  725.   ButtonList.Free;
  726.   SpeedList.Free;
  727.   SpeedPointer.Free;
  728.   Offscreen.Free;
  729.   SampleBmp.Free;
  730. end;
  731.  
  732. function TAppExpert.HasMenus: Boolean;
  733. begin
  734.   Result := (cbFileMenu.Checked) or (cbEditMenu.Checked) or
  735.     (cbWindowMenu.Checked) or (cbHelpMenu.Checked);
  736. end;
  737.  
  738. { calculate which page is next based on current page and settings.
  739.   -1 = last page
  740.   -2 = cannot move in requested direction }
  741. function TAppExpert.NextPage(Direction: TMoveDirection): Integer;
  742. var
  743.   CurPage: Integer;
  744. begin
  745.   Result := -2;
  746.   CurPage := PageControl.ActivePage.PageIndex;
  747.  
  748.   case Direction of
  749.  
  750.     mdNoMove: if CurPage = LastPage then Result := -1
  751.       else Result := 0;
  752.  
  753.     mdPrevious:
  754.       begin
  755.         case CurPage of
  756.           pgMenus: begin { do nothing } end;
  757.           pgExtensions: Result := pgMenus;
  758.           pgSpeedbar: if cbFileMenu.Checked then Result := pgExtensions
  759.             else Result := pgMenus;
  760.           pgAppInfo: if HasMenus then Result := pgSpeedbar
  761.             else Result := pgMenus;
  762.         end;
  763.       end;
  764.  
  765.     mdNext:
  766.       begin
  767.         case CurPage of
  768.           pgMenus:
  769.             if cbFileMenu.Checked then Result := pgExtensions
  770.             else if HasMenus then Result := pgSpeedbar
  771.             else Result := pgAppInfo;
  772.           pgExtensions: Result := pgSpeedbar;
  773.           pgSpeedbar: Result := pgAppInfo;
  774.           pgAppInfo: Result := -1;
  775.         end;
  776.       end;
  777.   end;
  778. end;
  779.  
  780. procedure TAppExpert.RefreshButtons;
  781. begin
  782.   case NextPage(mdNoMove) of
  783.    -1: NextButton.Caption := LoadStr(sFinish);
  784.     0: NextButton.Caption := LoadStr(sNext);
  785.   end;
  786.   case NextPage(mdPrevious) of
  787.     -2: PrevButton.Enabled := False;
  788.     else PrevButton.Enabled := True;
  789.   end;
  790. end;
  791.  
  792. procedure RemoveItems(List: TList; MenuIndex: TMainItems);
  793. var
  794.   StartID: Integer;
  795.   EndID: Integer;
  796.   I: Integer;
  797.   ButtonImage: TButtonImage;
  798. begin
  799.   StartID := sMenuItemTextBase + MenuItemOffsets[MenuIndex];
  800.   EndID := StartID + MenuItemCounts[MenuIndex];
  801.  
  802.   I := 0;
  803.  
  804.   while I < List.Count do
  805.   begin
  806.     ButtonImage := TButtonImage(List[I]);
  807.     if (ButtonImage <> nil) and (ButtonImage.BitmapID < EndID) and
  808.       (ButtonImage.BitmapID >= StartID) then
  809.       List.Delete(I)
  810.     else Inc(I);
  811.   end;
  812. end;
  813.  
  814. procedure TAppExpert.MenuClicked(Sender: TObject);
  815. var
  816.   MenuIndex: TMainItems;
  817.   MenuOn: Boolean;
  818. begin
  819.   { a menu category has been turned on/off }
  820.   for MenuIndex := Low(TMainItems) to High(TMainItems) do
  821.   begin
  822.     case MenuIndex of
  823.       mmFile: MenuOn := cbFileMenu.Checked;
  824.       mmEdit: MenuOn := cbEditMenu.Checked;
  825.       mmWindow: MenuOn := cbWindowMenu.Checked;
  826.       mmHelp: MenuOn := cbHelpMenu.Checked;
  827.     end;
  828.     if not MenuOn then
  829.     begin
  830.       RemoveItems(SpeedList, MenuIndex);
  831.       FSpeedIndex := 0;
  832.     end;
  833.     if MenuList.ItemIndex = Ord(MenuIndex) then
  834.       MenuListClick(Self);
  835.   end;
  836. end;
  837.  
  838. function TAppExpert.ValidateInfo: Boolean;
  839. begin
  840.   Result := False;
  841.   if AppName.Text = '' then
  842.   begin
  843.     MessageDlg(LoadStr(sAppNameRequired), mtError, [mbOK], 0);
  844.     Exit;
  845.   end;
  846.   if not IsValidIdent(AppName.Text) then
  847.   begin
  848.     MessageDlg(LoadStr(sInvalidAppName), mtError, [mbOK], 0);
  849.     Exit;
  850.   end;
  851.   if not DirectoryExists(AppPath.Text) then
  852.   begin
  853.     MessageDlg(LoadStr(sInvalidPath), mtError, [mbOK], 0);
  854.     Exit;
  855.   end;
  856.   Result := True;
  857. end;
  858.  
  859. procedure TAppExpert.NextPrevClick(Sender: TObject);
  860. var
  861.   NewPage: Integer;
  862. begin
  863.   if Sender = PrevButton then NewPage := NextPage(mdPrevious)
  864.   else NewPage := NextPage(mdNext);
  865.  
  866.   case NewPage of
  867.    -1: if ValidateInfo then ModalResult := mrOK;
  868.    -2: begin { do nothing } end;
  869.     else
  870.     begin
  871.       if SampleBitmaps[NewPage] <> nil then
  872.       begin
  873.         SampleBmp.Handle := LoadBitmap(HInstance, SampleBitmaps[NewPage]);
  874.         Sample.Invalidate;
  875.       end;
  876.       PageControl.ActivePage := PageControl.Pages[NewPage];
  877.     end;
  878.   end;
  879.   RefreshButtons;
  880. end;
  881.  
  882. { draw the file extension list box }
  883. procedure TAppExpert.DrawExtension(Control: TWinControl; Index: Integer;
  884.   Rect: TRect; State: TOwnerDrawState);
  885. var
  886.   P: Integer;
  887.   R: TRect;
  888.   C: array[0..255] of Char;
  889.   S: string;
  890. begin
  891.   { find the separator in the string }
  892.   P := AnsiPos('|', ExtListBox.Items[Index]);
  893.  
  894.   { adjust the rectangle so we draw only the left "column" }
  895.   R := Rect;
  896.  
  897.   { draw the filter description }
  898.   S := Copy(ExtListBox.Items[Index], 1, P - 1);
  899.   R.Right := R.Left + ExtHeader.SectionWidth[0];
  900.   ExtTextOut(ExtListBox.Canvas.Handle, R.Left, R.Top, ETO_CLIPPED or
  901.     ETO_OPAQUE, @R, StrPCopy(C, S), Length(S), nil);
  902.  
  903.   { move the rectangle to the next column }
  904.   R.Left := R.Right;
  905.   R.Right := Rect.Right;
  906.   S := Copy(ExtListBox.Items[Index], P + 1, 255);
  907.   ExtTextOut(ExtListBox.Canvas.Handle, R.Left, R.Top, ETO_CLIPPED or
  908.     ETO_OPAQUE, @R, StrPCopy(C, S), Length(S), nil);
  909. end;
  910.  
  911. procedure TAppExpert.HeaderSized(Sender: TObject; ASection,
  912.   AWidth: Integer);
  913. begin
  914.   ExtListBox.Invalidate;
  915. end;
  916.  
  917. procedure TAppExpert.AddClick(Sender: TObject);
  918. var
  919.   Filter: string;
  920. begin
  921.   Filter := '';
  922.   if EditFilterInfo(Filter) then
  923.     ExtListBox.Items.Add(Filter);
  924. end;
  925.  
  926. procedure TAppExpert.EditClick(Sender: TObject);
  927. var
  928.   Filter: string;
  929. begin
  930.   if ExtListBox.ItemIndex > -1 then
  931.   begin
  932.     Filter := ExtListBox.Items[ExtListBox.ItemIndex];
  933.     if EditFilterInfo(Filter) then
  934.       ExtListBox.Items[ExtListBox.ItemIndex] := Filter;
  935.   end;
  936. end;
  937.  
  938. procedure TAppExpert.DeleteClick(Sender: TObject);
  939. begin
  940.   if ExtListBox.ItemIndex > -1 then
  941.     ExtListBox.Items.Delete(ExtListBox.ItemIndex);
  942. end;
  943.  
  944. procedure TAppExpert.MoveClick(Sender: TObject);
  945. var
  946.   Delta: Integer;
  947.   NewPos: Integer;
  948. begin
  949.   if ExtListBox.ItemIndex <> -1 then
  950.   begin
  951.     if Sender = UpButton then Delta := -1
  952.     else if Sender = DownButton then Delta := 1
  953.     else Delta := 0;
  954.  
  955.     if Delta <> 0 then
  956.     begin
  957.       NewPos := ExtListBox.ItemIndex + Delta;
  958.       if (NewPos >= 0) and (NewPos < ExtListBox.Items.Count) then
  959.       begin
  960.         ExtListBox.Items.Move(ExtListBox.ItemIndex, NewPos);
  961.         ExtListBox.ItemIndex := NewPos;
  962.       end;
  963.     end;
  964.   end;
  965. end;
  966.  
  967. { return the rectangle of the specified speedbutton or space }
  968. function TAppExpert.SpeedButtonRect(Index: Integer): TRect;
  969. var
  970.   I: Integer;
  971.   X: Integer;
  972. begin
  973.   X := 10;  { first usable position }
  974.  
  975.   for I := 0 to Index - 1 do
  976.     if SpeedList[I] = nil then Inc(X, DefaultButtonSpace)
  977.     else Inc(X, DefaultButtonSize.X - 1);
  978.  
  979.   Result := Bounds(X, 5, DefaultButtonSize.X, DefaultButtonSize.Y);
  980.   if (Index < SpeedList.Count) and (SpeedList[Index] = nil) then
  981.     Result.Right := Result.Left + DefaultButtonSpace;
  982. end;
  983.  
  984. { return an index into SpeedList from the TPoint }
  985. function TAppExpert.SpeedButtonAtPos(Pos: TPoint): Integer;
  986. var
  987.   R: TRect;
  988.   I: Integer;
  989. begin
  990.   for I := 0 to SpeedList.Count - 1 do
  991.   begin
  992.     R := SpeedButtonRect(I);
  993.     if PtInRect(R, Pos) then
  994.     begin
  995.       Result := I;
  996.       Exit;
  997.     end;
  998.   end;
  999.   Result := -1;
  1000. end;
  1001.  
  1002. function TAppExpert.GetSpeedButtonCount: Integer;
  1003. begin
  1004.   Result := SpeedList.Count;
  1005. end;
  1006.  
  1007. function TAppExpert.GetSpeedButtonID(Value: Integer): Integer;
  1008. var
  1009.   ButtonImage: TButtonImage;
  1010. begin
  1011.   ButtonImage := TButtonImage(SpeedList[Value]);
  1012.   if ButtonImage <> nil then Result := ButtonImage.BitmapID
  1013.   else Result := -1;
  1014. end;
  1015.  
  1016. procedure TAppExpert.SpeedbarPaint(Sender: TObject);
  1017. var
  1018.   I: Integer;
  1019.   ButtonImage: TButtonImage;
  1020.   X: Integer;
  1021.   R: TRect;
  1022. begin
  1023.   with Offscreen.Canvas do
  1024.   begin
  1025.     Pen.Color := clWindowFrame;
  1026.     Brush.Style := bsClear;
  1027.     Brush.Color := SpeedBar.Color;
  1028.  
  1029.     Rectangle(1, 1, SpeedBar.Width - 1, SpeedBar.Height - 1);
  1030.     Pen.Color := clBtnShadow;
  1031.     PolyLine([Point(0, Speedbar.Height - 1), Point(0, 0),
  1032.       Point(SpeedBar.Width - 1, 0)]);
  1033.     Pen.Color := clBtnHighlight;
  1034.     PolyLine([ Point(SpeedBar.Width - 1, 0),
  1035.       Point(SpeedBar.Width - 1, SpeedBar.Height)]);
  1036.   end;
  1037.  
  1038.   { Draw the buttons in the list }
  1039.   X := 10;
  1040.   for I := 0 to SpeedList.Count - 1 do
  1041.   begin
  1042.     ButtonImage := TButtonImage(SpeedList[I]);
  1043.     if ButtonImage = nil then
  1044.     begin
  1045.       Offscreen.Canvas.Brush.Style := bsSolid;
  1046.       Offscreen.Canvas.Brush.Color := clBtnShadow;
  1047.       R := Bounds(X + 2, 5, DefaultButtonSpace - 3, DefaultButtonSize.Y - 2);
  1048.       Offscreen.Canvas.FillRect(R);
  1049.       Inc(X, DefaultButtonSpace);
  1050.     end
  1051.     else
  1052.     begin
  1053.       Offscreen.Canvas.Brush.Style := bsSolid;
  1054.       ButtonImage.Draw(Offscreen.Canvas, X, 4);
  1055.       Inc(X, DefaultButtonSize.X - 1);
  1056.     end;
  1057.  
  1058.     if X + (DefaultButtonSize.X * 2) > SpeedBar.Width then Break;
  1059.  
  1060.     { draw the insertion point }
  1061.     R := SpeedButtonRect(FSpeedIndex);
  1062.     OffsetRect(R, -5, 0);
  1063.     R.Top := R.Bottom + 2;
  1064.     R.Bottom := R.Top + SpeedPointer.Height;
  1065.     R.Right := R.Left + SpeedPointer.Width;
  1066.     Offscreen.Canvas.Brush.Color := SpeedBar.Color;
  1067.     Offscreen.Canvas.BrushCopy(R, SpeedPointer, Rect(0, 0, SpeedPointer.Width,
  1068.       SpeedPointer.Height), clWhite);
  1069.   end;
  1070.   SpeedBar.Canvas.Draw(0, 0, Offscreen);
  1071. end;
  1072.  
  1073. { The list of menus was clicked }
  1074. procedure TAppExpert.MenuListClick(Sender: TObject);
  1075. var
  1076.   ID: Word;
  1077.   I: Integer;
  1078.   ButtonIndex: Integer;
  1079.   MenuOn: Boolean;
  1080. begin
  1081.   if MenuList.ItemIndex > -1 then
  1082.   begin
  1083.     ID := sMenuItemTextBase + MenuItemOffsets[ TMainItems(MenuList.ItemIndex) ];
  1084.  
  1085.     MenuItemList.Items.BeginUpdate;
  1086.  
  1087.     try
  1088.       MenuItemList.Clear;
  1089.  
  1090.       case MenuList.ItemIndex of
  1091.         0: MenuOn := cbFileMenu.Checked;
  1092.         1: MenuOn := cbEditMenu.Checked;
  1093.         2: MenuOn := cbWindowMenu.Checked;
  1094.         3: MenuOn := cbHelpMenu.Checked;
  1095.       end;
  1096.  
  1097.       if MenuOn then
  1098.       begin
  1099.         { load the list box with the buttons and text }
  1100.         for I := 0 to MenuItemCounts[ TMainItems(MenuList.ItemIndex) ] - 1 do
  1101.         begin
  1102.           ButtonIndex := I + MenuItemOffsets[ TMainItems(MenuList.ItemIndex) ];
  1103.           MenuItemList.Items.AddObject(LoadStr(ID + I), ButtonList[ButtonIndex]);
  1104.         end;
  1105.       end;
  1106.  
  1107.     finally
  1108.       MenuItemList.Items.EndUpdate;
  1109.     end;
  1110.   end;
  1111. end;
  1112.  
  1113. procedure TAppExpert.DrawMenuItem(Control: TWinControl; Index: Integer;
  1114.   Rect: TRect; State: TOwnerDrawState);
  1115. var
  1116.   ButtonImage: TButtonImage;
  1117.   R: TRect;
  1118.   C: array[0..255] of Char;
  1119. begin
  1120.   ExtTextOut(MenuItemList.Canvas.Handle, R.Left, R.Top, ETO_OPAQUE,
  1121.     @Rect, nil, 0, nil);
  1122.   ButtonImage := TButtonImage(MenuItemList.Items.Objects[Index]);
  1123.   ButtonImage.Draw(MenuItemList.Canvas, Rect.Left + 2, Rect.Top + 1);
  1124.  
  1125.   R := Rect;
  1126.   Inc(R.Left, DefaultButtonSize.X + 2 + 4);
  1127.   DrawText(MenuItemList.Canvas.Handle,
  1128.     StrPCopy(C, MenuItemList.Items[Index]), -1, R, DT_VCENTER or DT_SINGLELINE);
  1129. end;
  1130.  
  1131. { Insert the current button into the speedbar }
  1132. procedure TAppExpert.InsertClick(Sender: TObject);
  1133. var
  1134.   ButtonImage: TButtonImage;
  1135. begin
  1136.   if MenuItemList.ItemIndex > -1 then
  1137.   begin
  1138.     with MenuItemList do
  1139.       ButtonImage := TButtonImage(Items.Objects[ItemIndex]);
  1140.     if FSpeedIndex < SpeedList.Count then
  1141.       SpeedList.Insert(FSpeedIndex, ButtonImage)
  1142.     else
  1143.       SpeedList.Add(ButtonImage);
  1144.     Inc(FSpeedIndex);
  1145.     SpeedBar.Invalidate;
  1146.   end;
  1147. end;
  1148.  
  1149. procedure TAppExpert.SpaceClick(Sender: TObject);
  1150. begin
  1151.   if FSpeedIndex < SpeedList.Count then
  1152.     SpeedList.Insert(FSpeedIndex, nil)
  1153.   else
  1154.     SpeedList.Add(nil);
  1155.   Inc(FSpeedIndex);
  1156.   SpeedBar.Invalidate;
  1157. end;
  1158.  
  1159. procedure TAppExpert.RemoveClick(Sender: TObject);
  1160. begin
  1161.   if FSpeedIndex < SpeedList.Count then
  1162.   begin
  1163.     SpeedList.Delete(FSpeedIndex);
  1164.     if FSpeedIndex > SpeedList.Count then
  1165.       FSpeedIndex := SpeedList.Count;
  1166.     SpeedBar.Invalidate;
  1167.   end;
  1168. end;
  1169.  
  1170. { The mouse was clicked in the speedbar area }
  1171. procedure TAppExpert.SpeedMouseDown(Sender: TObject; Button: TMouseButton;
  1172.   Shift: TShiftState; X, Y: Integer);
  1173. var
  1174.   Index: Integer;
  1175. begin
  1176.   Index := SpeedButtonAtPos(Point(X, Y));
  1177.   if Index <> -1 then FSpeedIndex := Index
  1178.   else FSpeedIndex := SpeedList.Count;
  1179.   Speedbar.Invalidate;
  1180. end;
  1181.  
  1182. procedure TAppExpert.BrowseClick(Sender: TObject);
  1183. var
  1184.   D: string;
  1185. begin
  1186.   D := AppPath.Text;
  1187.   if SelectDirectory(D, [sdAllowCreate, sdPrompt, sdPerformCreate], 0) then
  1188.     AppPath.Text := D;
  1189. end;
  1190.  
  1191. procedure TAppExpert.SamplePaint(Sender: TObject);
  1192. begin
  1193.   if SampleBmp <> nil then
  1194.     Sample.Canvas.Draw(0, 0, SampleBmp);
  1195. end;
  1196.  
  1197. end.
  1198.